#define _GNU_SOURCE
#include <limits.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/random.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet/ether.h>
#include <netinet/ip_icmp.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>

int connect_cdn(const char *ip)
{
	struct addrinfo hints, *result;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;

	getaddrinfo(ip, "23", &hints, &result);
	int fd = -1;
	for (struct addrinfo *rp = result; rp; rp = rp->ai_next) {
		fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		if (fd < 0) {
			continue;
		}
		if (connect(fd, rp->ai_addr, rp->ai_addrlen) < 0) {
			perror("connect");
			close(fd);
			fd = -1;
			continue;
		}
		freeaddrinfo(result);
		return fd;
	}
	freeaddrinfo(result);
	return -1;
}

#define SE 240
#define SB 250
#define WILL 251
#define DO 253
#define WONT 252
#define DONT 254
#define IAC 255

void deal_contrl(int fd)
{
	u_char buf[512], out[512], data[512];
	int len = 0, olen = 0, dlen = 0;
	while ((len = read(fd, buf, sizeof(buf))) > 0) {
		for (int i = 0; i < len; i++) {
			fprintf(stderr, "%u ", buf[i]);
		}
		for (int i = 0; i < len; i++) {
			if (buf[i] == IAC) {
				out[olen++] = buf[i++];

				switch (buf[i]) {
				case WILL:
					out[olen++] = DO;
					i++;
					out[olen++] = buf[i];
					break;
				case DO:
					out[olen++] = WILL;
					i++;
					out[olen++] = buf[i];
					break;
				case WONT:
					out[olen++] = DONT;
					i++;
					out[olen++] = buf[i];
					break;
				case DONT:
					out[olen++] = WONT;
					i++;
					out[olen++] = buf[i];
					break;
				case SB:
					out[olen++] = SB;
					i++;
					out[olen++] = buf[i];
					i++;
					out[olen++] = buf[i];
					break;
				case SE:
					out[olen++] = SE;
					break;
				default:
					continue;
				}
			} else {
				data[dlen++] = buf[i];
			}
		}
		write(fd, out, olen);
		printf("\nout = %d\n", olen);
		for (int i = 0; i < olen; i++) {
			fprintf(stderr, "%u ", out[i]);
		}
		break;
		olen = 0;
		if (dlen) {
			break;
		}
	}
	// printf("\nout = %d\n", olen);
	// for (int i = 0; i < olen; i++) {
	// 	fprintf(stderr, "%u ", out[i]);
	// }
	printf("\ndata\n");
	for (int i = 0; i < dlen; i++) {
		fprintf(stderr, "%u ", data[i]);
	}

	int pos = 0;
	while ((len = recv(fd, buf + pos, sizeof(buf) - pos, 0)) > 0) {
		pos += len;
		buf[pos] = 0;
		fprintf(stderr, "#%s", buf);
	}
}

int send_cmd(char *cmd, const char *ip)
{
	int fd = connect_cdn(ip);
	if (fd < 0) {
		return 0;
	}

	//deal_contrl(fd);

	struct timeval tv;
	tv.tv_sec = 5;
	tv.tv_usec = 0;
	setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

	fd_set rset, org_rset;
	FD_ZERO(&rset);
	FD_ZERO(&org_rset);
	FD_SET(fd, &org_rset);
	FD_SET(fd, &rset);

	char username[] = "linaro";
	char passwd[] = "linarosjy";
	u_char buf[512];
	int pos = 0, len = 0;
	for (;;) {
		int ret = select(fd + 1, &rset, NULL, NULL, NULL);
		if (ret < 0) {
			return -1;
		}
		len = read(fd, buf + pos, sizeof(buf) - pos);
		pos += len;
		buf[pos] = 0;
		if (buf[0] == 0xFF) {
			for (int i = 0; i < len; i++) {
				if (buf[i] == 251) {
					buf[i] = 253;
				}
				fprintf(stderr, "%02x ", buf[i]);
			}
			write(fd, buf, len);
			pos = 0;
			rset = org_rset;
			continue;
		}
		break;
		rset = org_rset;
	}

	pos = 0;
	while ((len = recv(fd, buf + pos, sizeof(buf) - pos, 0)) > 0) {
		pos += len;
		buf[pos] = 0;
		fprintf(stderr, "*%s", buf);
		if (strstr((char *)buf, "login:")) {
			write(fd, username, strlen(username));
			write(fd, "\n", 1);
			break;
		}
	}
	pos = 0;
	while ((len = recv(fd, buf + pos, sizeof(buf) - pos, 0)) > 0) {
		pos += len;
		buf[pos] = 0;
		fprintf(stderr, "#%s", buf);
		if (strstr((char *)buf, "Password:")) {
			write(fd, passwd, strlen(passwd));
			write(fd, "\n", 1);
			break;
		}
	}

	pos = 0;
	while ((len = recv(fd, buf, sizeof(buf), 0)) > 0) {
		buf[len] = 0;
		fprintf(stderr, "$%s", buf);
		if (strstr((char *)buf, "alip:~$")) {
			write(fd, cmd, strlen(cmd));
			write(fd, "\n", 1);
			break;
		}
	}

	pos = 0;
	while ((len = recv(fd, buf + pos, sizeof(buf) - pos, 0)) > 0) {
		pos += len;
		buf[pos] = 0;
		fprintf(stderr, "$%s", buf);
		if (strstr((char *)buf, "alip:~$")) {
			break;
		}
	}
	return 0;
}

int main()
{
	send_cmd("ls /", "10.110.30.151");
	return 0;
}